﻿using System;
using System.Collections.Generic;
using Framework;

public class EventManager : Manager 
{
    enum EventTypeEnum
    {
        INT,
        STRING
    }

    class XEvent
    {
        public EventTypeEnum EventType;
        public int id;
        public string strId;
        public object param;
    }

    private Dictionary<int, Action<object>> _eventMap = new Dictionary<int, Action<object>>();
    private Dictionary<string, Action<object>> _strEventMap = new Dictionary<string, Action<object>>();
    private Queue<XEvent> _tobeDispatchedEvents = new Queue<XEvent>();
    private int mainThreadId;
    public bool IsMainThread
    {
        get { return System.Threading.Thread.CurrentThread.ManagedThreadId == mainThreadId; }
    }

    #region Unity lifecycle
    void Awake()
    {
        mainThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
    }

    new void Update()
    {
        XEvent e;
        lock (_tobeDispatchedEvents)
        {
            e = null;
            if(_tobeDispatchedEvents.Count > 0)
                e = _tobeDispatchedEvents.Dequeue();
        }
        while (e != null)
        {
            if (e.EventType == EventTypeEnum.INT)
            {
                if (_eventMap.ContainsKey(e.id) && _eventMap[e.id] != null)
                {
                    _eventMap[e.id].Invoke(e.param);
                }
                if (AppFacade.luaManager.lua != null)
                    AppFacade.luaManager.lua.Call<int, object>("EVTM.dispatch", (int)e.id, e.param, false);
            }
            else
            {
                if (_strEventMap.ContainsKey(e.strId) && _strEventMap[e.strId] != null)
                {
                    _strEventMap[e.strId].Invoke(e.param);
                }
                if (AppFacade.luaManager.lua != null)
                    AppFacade.luaManager.lua.Call<string, object>("EVTM.dispatch", e.strId, e.param, false);
            }

            lock (_tobeDispatchedEvents)
            {
                e = null;
                if (_tobeDispatchedEvents.Count > 0)
                    e = _tobeDispatchedEvents.Dequeue();
            }
        }
        
    }
    #endregion

    public void RegisterEvent(int id, Action<object> callback)
    {
        if (_eventMap.ContainsKey(id))
        {
            _eventMap[id] += callback;
        }
        else
        {
            _eventMap[id] = callback;
        }
    }

    public void RegisterEvent(string id, Action<object> callback)
    {
        if (_strEventMap.ContainsKey(id))
        {
            _strEventMap[id] += callback;
        }
        else
        {
            _strEventMap[id] = callback;
        }
    }

    public void UnregisterEvent(int id, Action<object> callback)
    {
        if (!_eventMap.ContainsKey(id))
        {
            return;
        }

        _eventMap[id] -= callback;
        if (_eventMap[id] == null)
        {
            _eventMap.Remove(id);
        }
    }

    public void UnregisterEvent(string id, Action<object> callback)
    {
        if (!_strEventMap.ContainsKey(id))
        {
            return;
        }

        _strEventMap[id] -= callback;
        if (_strEventMap[id] == null)
        {
            _strEventMap.Remove(id);
        }
    }

    public void DispatchEvent(int id, object param = null)
    {
        if (IsMainThread)
        {
            if (_eventMap.ContainsKey(id) && _eventMap[id] != null)
            {
                _eventMap[id].Invoke(param);
            }

            AppFacade.luaManager.lua.Call<int, object>("EVTM.dispatch", (int)id, param, false);
        }
        else
        {
            XEvent enlistEvent = new XEvent();
            enlistEvent.EventType = EventTypeEnum.INT;
            enlistEvent.id = id;
            enlistEvent.param = param;
            lock(_tobeDispatchedEvents)
            {
                _tobeDispatchedEvents.Enqueue(enlistEvent);
            }
        }
    }

    public void DispatchEvent(string id, object param = null)
    {
        if (IsMainThread)
        {
            if (_strEventMap.ContainsKey(id) && _strEventMap[id] != null)
            {
                _strEventMap[id].Invoke(param);
            }
            if(AppFacade.luaManager.lua!=null)
            AppFacade.luaManager.lua.Call<string, object>("EVTM.dispatch", id, param, false);
        }
        else
        {
            XEvent enlistEvent = new XEvent();
            enlistEvent.EventType = EventTypeEnum.STRING;
            enlistEvent.strId = id;
            enlistEvent.param = param;
            lock(_tobeDispatchedEvents)
            {
                _tobeDispatchedEvents.Enqueue(enlistEvent);
            }
        }
    }

    

    public void Clear()
    {
        _eventMap.Clear();
    }
}